package edu.isistan.matching.utils;

import java.util.HashMap;


import org.apache.log4j.Logger;

import edu.isistan.matching.structures.elements.PartElement;
import edu.isistan.matching.structures.elements.TypeElement;
import edu.isistan.matching.structures.elements.WSDLElement;
import edu.isistan.matching.structures.elements.types.ElementType;
import edu.isistan.metamodel.DataType;

public class WSDLTypes2Interface {

	static Logger logger = Logger.getLogger(WSDLTypes2Interface.class);
	
	private static final String URN = "urn:";
	private static final String HTTP = "http://";
	private static final String URI = "uri://";

	private static HashMap<String, String> PRIMITIVES = new HashMap<String, String>();
	private static HashMap<String, String> WRAPPERS = new HashMap<String, String>();

	static {
		PRIMITIVES.put("base64Binary", "byte[]");
		PRIMITIVES.put("boolean", "boolean");
		PRIMITIVES.put("byte", "byte");
		PRIMITIVES.put("dateTime", "java.util.Calendar");
		PRIMITIVES.put("decimal", "java.math.BigDecimal");
		PRIMITIVES.put("double", "double");
		PRIMITIVES.put("float", "float");
		PRIMITIVES.put("hexBinary", "byte[]");
		PRIMITIVES.put("int", "int");
		PRIMITIVES.put("integer", "java.math.BigInteger");
		PRIMITIVES.put("long", "long");
		PRIMITIVES.put("QName", "javax.xml.namespace.QName");
		PRIMITIVES.put("short", "short");
		PRIMITIVES.put("string", "java.lang.String");
		PRIMITIVES.put("Number", "java.lang.Number");

		WRAPPERS.put("base64Binary", "byte[]");
		WRAPPERS.put("boolean", "java.lang.Boolean");
		WRAPPERS.put("byte", "java.lang.Byte");
		WRAPPERS.put("dateTime", "java.util.Calendar");
		WRAPPERS.put("decimal", "java.math.BigDecimal");
		WRAPPERS.put("double", "java.lang.Double");
		WRAPPERS.put("float", "java.lang.Float");
		WRAPPERS.put("hexBinary", "byte[]");
		WRAPPERS.put("int", "java.lang.Integer");
		WRAPPERS.put("integer", "java.math.BigInteger");
		WRAPPERS.put("long", "java.lang.Long");
		WRAPPERS.put("QName", "javax.xml.namespace.QName");
		WRAPPERS.put("short", "java.lang.Short");
		WRAPPERS.put("string", "java.lang.String");
		WRAPPERS.put("Number", "java.lang.Number");
	}

	public static boolean representAClass(DataType element) {
		return (!element.isPrimitive() && hasInterfaceMapping(element));
	}

	public static boolean representAnAttribute(TypeElement element) {
		return element.isPrimitivo();
	}

	public static boolean hasInterfaceMapping(DataType element) {
		boolean retorno = true;
		if (!element.isPrimitive()) {
			return false;
		}
		return retorno;
	}

	public static String getAttributeName(DataType element) {
		return element.getName();
	}

	public static String getAttributeName(DataType element, String partName) {
		DataType parent = element.getContainedIn();
		if (parent!=null) {
			return parent.getName();
		} else {
			return element.getName();
		}
	}

	public static String getWSDLTypeName(TypeElement element) {
		WSDLElement parent = element.getParentElement();
		if (!element.isPrimitivo() && (parent instanceof ElementType)) {
			return ((ElementType) parent).getType();
		} else if (!element.isPrimitivo() && (parent instanceof PartElement)) {
			return element.getName();
		} else {
			return element.getType();
		}
	}

	public static String getJavaType(TypeElement element) {
		String wsdlType = getWSDLTypeName(element);
		String tipoJava = "";
		if (element.isPrimitivo()) {
			
			if (element.isAnyType()) {
				tipoJava = "java.lang.Object";
			} else {
				// Se valida si el tipo java es primitivo o wrapper a primitivo
				if (element.isNillable()) {
					tipoJava = WRAPPERS.get(wsdlType);
				} else {
					tipoJava = PRIMITIVES.get(wsdlType);
				}
			}
		} else {
			// Se valida el nombre del paquete que contiene la clase compleja
			tipoJava = parsePackage(element.getTargetNameSpace());
			if (tipoJava != null) {

				tipoJava += "." + wsdlType;
			} else {
				tipoJava = wsdlType;
			}
		}
		
		return tipoJava;
	}

	public static String parsePackage(String namespace) {
		logger.info("NAMESPACE: "+namespace);
		String packageName = null;
		try {
			if (namespace != null) {
				namespace = namespace.trim();
				int offSet = 0;
				if (namespace.startsWith(URN)) {
					offSet = URN.length();
				} else if (namespace.startsWith(HTTP)) {
					offSet = HTTP.length();
				} else if (namespace.startsWith(URI)) {
					offSet = URI.length();
				} else {
					// Se valida algun tipo especial de URI
					// cualquier_uri://example.com
					int auxOffSet = namespace.indexOf("://");
					if (auxOffSet >= 0) {
						auxOffSet += "://".length();
						offSet = auxOffSet;
					}
				}
				packageName = "";
				String url = namespace.substring(offSet);
				int first = url.indexOf("/");
				if (first > 0) {
					url = url.substring(0, first);
				}
				// Se valida si el url tiene un puerto asociado y se lo elimina
				if (url.contains(":")) {
					url = url.split(":")[0];
				}
				String[] pack = url.split("\\.");
				for (int e = pack.length - 1; e >= 0; e--) {
					packageName += pack[e];
					if (e > 0) {
						packageName += ".";
					}
				}
				if (first > 0) {
					String rest = namespace.substring(first + offSet);
					if (rest.length() > 1) {
						rest = rest.replaceAll("\\.", "_");
						packageName += rest.replaceAll("/", "\\.");
					}
				}
			}
			if (packageName.endsWith(".")) {
				packageName = packageName.substring(0, packageName.length() - 1);
			}
		} catch (Exception e) {
			packageName = null;
			logger.error("Ocurrio un error al parsear el nombre del paquete");
			logger.error(e);
		}
		logger.info("INTERFAZ: "+packageName);
		return packageName;
	}
}
